﻿using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

using BaseThing.Game;

namespace BaseThing.Engine
{
    public enum SpriteState
    {
        BEGIN = 0,
        PLAYING,
        END,
    }

    class Sprite
    {
        int tilesCols    = 0;
        int tilesRows    = 0;

        int tileWidth    = 0;
        int tileHeight   = 0;

        int currentFrame = 0;
        int totalFrames;

        int startFrame = 0;
        int endFrame   = 0;

        double frameInterval = 0;
        double frameTimeRemaning = 0;

        protected Texture2D texture;
        protected Vector2 position;
        protected Vector2 origin;
        protected float rotation;
        protected float scale;
        protected int alpha;
        protected Color color;

        bool isPlay = true;
        bool isVisible = true;

        SpriteEffects spriteEffects = SpriteEffects.None;
        SpriteState status = SpriteState.BEGIN;

        public Sprite(string assetName, int tilesCols, int tilesRows,double frameRate)
        {
            texture = Config.GetContentManager().Load<Texture2D>(assetName);

            this.tilesCols = tilesCols;
            this.tilesRows = tilesRows;

            tileWidth = texture.Width / tilesCols;
            tileHeight = texture.Height / tilesRows;

            position = Vector2.Zero;
            rotation = 0.0f;
            scale = 1.0f;
            alpha = 255;
            color = new Color(255, 255, 255, alpha);

            frameInterval = 1 / frameRate;
            totalFrames = tilesCols * tilesRows;
            endFrame = totalFrames;
        }

        public Rectangle GetBounds()
        {
            int posX = (currentFrame % tilesCols) * tileWidth;
            int posY = (currentFrame / tilesCols) * tileHeight;

            return new Rectangle(posX, posY, tileWidth, tileHeight);
        }

        public Vector2 Position
        {
            set { position = value; }
            get { return position; }
        }

        public float Rotation
        {
            set { rotation = value; }
            get { return rotation; }
        }

        public float Scale
        {
            set { scale = value; }
            get { return scale; }
        }

        public int Alpha
        {
            set
            {
                if (value >= 0 && value <= 255)
                {
                    alpha = value;
                }
                else
                {
                    alpha = 255;
                }

                color = new Color(255, 255, 255, alpha);
            }

            get { return alpha; }
        }

        public bool Visible
        {
            set { isVisible = value; }
            get { return isVisible; }
        }

        public void Rotate(float l_fRotation)
        {
            this.rotation = l_fRotation;
        }

        public void RotateFromPoint(float l_fRotation, Vector2 l_vOrigin)
        {
            this.rotation = l_fRotation;
            this.origin = l_vOrigin;
        }

        public void ScaleFromPoint(float l_fScale, Vector2 l_vOrigin)
        {
            this.scale = l_fScale;
            this.origin = l_vOrigin;
        }

        public void RotateFromCenter(float l_fRotation)
        {
            this.rotation = l_fRotation;
            origin = new Vector2(tileWidth / 2, tileHeight / 2);
        }

        public void ScaleFromCenter(float l_fScale)
        {
            this.scale = l_fScale;
            origin = new Vector2(tileWidth / 2, tileHeight / 2);
        }

        public void Move(Vector2 l_Direction)
        {
            position = position + l_Direction;
        }

        public void Play()
        {
            isPlay = true;
        }

        public void Pause()
        {
            isPlay = false;
        }
        public void Stop(int stopFrame)
        {
            isPlay = false;

            if (currentFrame != (stopFrame  - 1))
                currentFrame = stopFrame - 1;
        }

        public SpriteState Status
        {
            set { this.status = value;  }
            get { return status; }
        }

        public SpriteEffects SpriteEffects
        {
            set { if (spriteEffects != value ) spriteEffects = value; }
            get { return spriteEffects; }
        }

        public Texture2D Texture
        {
            set { }
            get { return texture; }
        }


        //Ejecuta una animacion de una fila en concreto, tomando todas sus columnas
        public void SetAnimation(int row){

            isPlay = true;

            this.startFrame = row;
            this.endFrame = row * tilesCols;

            if (!(currentFrame >= startFrame && currentFrame <= endFrame))
                currentFrame = startFrame;

        }

        public void SetAnimation(int startFrame,int endFrame)
        {
            isPlay = true;
            this.startFrame = startFrame;
            this.endFrame = endFrame;

            if (!(currentFrame >= startFrame && currentFrame <= endFrame))
                currentFrame = startFrame;
        }

        public void SetAnimation(Point animation)
        {
            /*
            this.startFrame = tilesCols * animation.X; // Fila
            this.endFrame = this.startFrame + animation.Y ;  //Columnas 
            */

             isPlay = true;
             this.startFrame = animation.X - 1; // Fila
             this.endFrame = animation.Y;  //Columnas 

            //Si el frame actual no esta en el rango nuevo, se reasigna
             if ( !( currentFrame >=  startFrame && currentFrame <= endFrame) )
                currentFrame = startFrame;
        }

        public void SetMask(Color maskedColor)
        {

            Color[] textureData = new Color[texture.Width * texture.Height];
            texture.GetData<Color>(textureData);

            //Recorremos cada Pixel
            for (int y = 0; y < texture.Height; y++)
            {
                for (int x = 0; x < texture.Width; x++)
                {
                    //Obtenemos la posicion de forma lineal
                    int pos = x + (y * texture.Width);

                    //Si es el color que buscamos
                    if (maskedColor == textureData[pos])
                    {
                        textureData[pos] = Color.Transparent;
                    }
                }
            }

            //Asignamos de nuevo
            texture.SetData<Color>(textureData);
        }

        public virtual void Update(GameTime gameTime)
        {
            frameTimeRemaning -= gameTime.ElapsedGameTime.TotalSeconds;

            if (frameTimeRemaning <= 0)
            {
                //Only if this is true, animate
                if (isPlay)
                {
                   
                    if (currentFrame == startFrame) status = SpriteState.BEGIN;

                    currentFrame++;

                    if (currentFrame >= endFrame)
                    {
                        currentFrame = startFrame;
                        status = SpriteState.END;
                    }
                    else
                    {
                        status = SpriteState.PLAYING;
                    }
                }

                frameTimeRemaning = frameInterval;
            }
        }

        public virtual void Draw(SpriteBatch spriteBatch)
        {
            if (isVisible)
                spriteBatch.Draw(texture, position, GetBounds(), color, rotation, origin, scale, spriteEffects, 0f);
        }
    }
}
